﻿// <copyright file="Shape.cs" company="ThorIndustry">Copyright (c) ThorIndustry. All rights reserved.</copyright>

using System.Collections.Generic;

public partial class MouseInputManager : UnityEngine.MonoBehaviour
{
    private PuzzleView puzzleView;

    private bool isDragging = false;
    private bool isDown = false;
    private UnityEngine.Vector3 mousePositionOnDown;
    private UnityEngine.Vector3 shapeOffset;
    private UnityEngine.Vector2 worldLimit;

    private UnityEngine.Color previousHighlightColor;

    private Shape[] orderedShapes;

    public Shape HighlightedShape
    {
        get;
        private set;
    }

    public Shape SelectedShape
    {
        get;
        private set;
    }

    public void FlipSelectedShape()
    {
        if (this.SelectedShape != null)
        {
            this.SelectedShape.FlipVertically(this.SelectedShape.GetCenter());
        }
    }

    public void Hide()
    {
        this.orderedShapes = new Shape[0];
        this.SelectedShape = null;
        this.HighlightedShape = null;

        this.HideOverlay();
    }

    public void Initialize(PuzzleView puzzleView)
    {
        this.puzzleView = puzzleView;

        this.InitializeOverlay();
        this.HideOverlay();

    }

    public void Release()
    {
        this.puzzleView = null;
    }

    public void Show()
    {
        this.orderedShapes = new Shape[this.puzzleView.Shapes.Length];
        for (int index = 0; index < this.orderedShapes.Length; ++index)
        {
            this.orderedShapes[index] = this.puzzleView.Shapes[index];
            this.orderedShapes[index].SelectionIndex = index;
        }

        this.ShowOverlay();
        this.ChangeFlipButtonEnable(false);
    }

    protected virtual void Update()
    {
        if (this.puzzleView == null ||
            this.puzzleView.Shapes == null)
        {
            return;
        }

        if (this.puzzleView.HasEnded)
        {
            this.ChangeSelection(null);
            return;
        }

        // Check for back.
        if (UnityEngine.Input.GetKeyUp(UnityEngine.KeyCode.Escape))
        {
            // this.puzzleView.ViewService.Activate(typeof(OutGameView));
            this.puzzleView.ViewService.Activate(typeof(WelcomeView));
            return;
        }

        // Check if the mouse is over the overlay button...
        if (this.IsMouseOverButtons())
        {
            return;
        }

        // Highlight shape under the mouse.
        UnityEngine.Vector3 worldMousePosition = this.GetPosition();

        if (this.UpdateTouch())
        {
            // Try to avoid jumping when releasing one of the two finger.
            this.mousePositionOnDown = worldMousePosition;
            return;
        }

        if (!this.isDown)
        {
            bool over = false;
            for (int index = this.orderedShapes.Length - 1; index >= 0; --index)
            {
                if (this.orderedShapes[index].IsInTheShape(worldMousePosition))
                {
                    // Highlight it.
                    this.ChangeHightlight(this.orderedShapes[index]);

                    over = true;
                    break;
                }
            }

            if (!over)
            {
                this.ChangeHightlight(null);
            }
        }

        // We are over something.
        // Is the mouse button down?
        if (this.IsButtonDown())
        {
            // Mouse button down.
            if (this.SelectedShape != this.HighlightedShape &&
                this.HighlightedShape != null)
            {
                // Change selection.
                this.ChangeSelection(this.HighlightedShape);
            }

            this.mousePositionOnDown = worldMousePosition;
            this.isDown = true;
        }

        if (this.IsButtonUp())
        {
            if (this.SelectedShape != null)
            {
                this.SelectedShape.Snap(this.puzzleView.SolutionShape);

                if (this.HighlightedShape == null &&
                    !this.isDragging)
                {
                    this.ChangeSelection(null);
                }
            }

            this.isDown = false;
            this.isDragging = false;
        }

        if (this.SelectedShape != null)
        {
            // Check for rotation.
            float mouseScroll = UnityEngine.Input.GetAxis("Mouse ScrollWheel");
            if (mouseScroll != 0)
            {
                // Compute barycenter.
                this.SelectedShape.transform.RotateAround(this.SelectedShape.GetCenter(), UnityEngine.Vector3.forward, 15 * mouseScroll);
            }
        }
        
        if (this.isDown &&
            this.SelectedShape != null)
        {
            if (!this.isDragging)
            {
                // Check if the drag has started.
                if (UnityEngine.Vector3.SqrMagnitude(this.mousePositionOnDown - worldMousePosition) > 0.05f)
                {
                    // Drag started.
                    this.isDragging = true;

                    this.shapeOffset = this.SelectedShape.transform.position - worldMousePosition;
                    this.shapeOffset.z = 0;
                }
            }
            else
            {
                // We are currently moving the selected shape.
                UnityEngine.Vector3 moveOffset = worldMousePosition - this.mousePositionOnDown;
                moveOffset.z = 0;

                // Clamp the shape center in the viewport.
                moveOffset = this.SelectedShape.transform.position + moveOffset;
                this.SelectedShape.transform.position = this.SelectedShape.LimitPosition(moveOffset);

                this.mousePositionOnDown = worldMousePosition;
            }
        }
    }

    private void ChangeHightlight(Shape newHighlightedShape)
    {
        // Highlight it.
        if (this.HighlightedShape != null)
        {
            if (this.HighlightedShape != this.SelectedShape)
            {
                this.HighlightedShape.renderer.material.color = this.HighlightedShape.ShapeColor;
            }
            else
            {
                this.SelectedShape.renderer.material.color = this.puzzleView.CurrentPaletteDefinition.SelectionColor.Color;
            }
        }

        this.HighlightedShape = newHighlightedShape;
        
        if (this.HighlightedShape != null)
        {
            
            this.HighlightedShape.renderer.material.color = this.HighlightedShape.renderer.material.color * 1.2f;
        }
    }

    private void ChangeSelection(Shape newSelectedShape)
    {
        // Select it.
        if (this.SelectedShape != null)
        {
            this.SelectedShape.renderer.material.color = this.SelectedShape.ShapeColor;
            this.SelectedShape.Snap(this.puzzleView.SolutionShape);
        }

        this.SelectedShape = newSelectedShape;

        if (this.SelectedShape != null)
        {
            this.SelectedShape.renderer.material.color = this.puzzleView.CurrentPaletteDefinition.SelectionColor.Color;

            int lastShapeIndex = this.SelectedShape.SelectionIndex;
            for (int index = lastShapeIndex + 1; index < this.orderedShapes.Length; ++index)
            {
                this.orderedShapes[index - 1] = this.orderedShapes[index];
                this.orderedShapes[index - 1].SelectionIndex = index - 1;
                this.orderedShapes[index - 1].RefreshZ();
            }

            this.SelectedShape.SelectionIndex = this.puzzleView.Shapes.Length - 1;
            this.orderedShapes[this.SelectedShape.SelectionIndex] = this.SelectedShape;
            this.SelectedShape.Snap(this.puzzleView.SolutionShape);
        }

        this.ChangeFlipButtonEnable(this.SelectedShape != null);
    }

    private bool IsButtonDown()
    {
#if (UNITY_IPHONE || UNITY_ANDROID)
        return UnityEngine.Input.touchCount == 1 &&
               UnityEngine.Input.touches[0].phase == UnityEngine.TouchPhase.Began;
#else
        return UnityEngine.Input.GetMouseButtonDown(0);
#endif
    }

    private bool IsButtonUp()
    {
#if (UNITY_IPHONE || UNITY_ANDROID)
        return UnityEngine.Input.touchCount == 1 &&
               (UnityEngine.Input.touches[0].phase == UnityEngine.TouchPhase.Ended ||
                UnityEngine.Input.touches[0].phase == UnityEngine.TouchPhase.Canceled);
#else
        return UnityEngine.Input.GetMouseButtonUp(0);
#endif
    }

    private UnityEngine.Vector3 GetPosition()
    {
#if (UNITY_IPHONE || UNITY_ANDROID)
        if (UnityEngine.Input.touchCount == 1)
        {
            return UnityEngine.Camera.main.ScreenToWorldPoint(UnityEngine.Input.touches[0].position);
        }
#endif
        return UnityEngine.Camera.main.ScreenToWorldPoint(UnityEngine.Input.mousePosition);
    }
}
